<template>
  <div class="tag-cloud">
    <canvas ref="canvas"></canvas>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';

interface Tag {
  name: string;
  color: string;
}

export default defineComponent({
  name: 'TagCloud',
  props: {
    tags: {
      type: Array as () => Tag[],
      required: true
    }
  },
  setup(props) {
    const canvas = ref<HTMLCanvasElement | null>(null);
    let ctx: CanvasRenderingContext2D | null = null;
    let tags: {
      text: string;
      x: number;
      y: number;
      z: number;
      color: string;
    }[] = [];
    let angleX = 0;
    let angleY = 0;
    let mouseX = 0;
    let mouseY = 0;

    const init = () => {
      if (canvas.value) {
        ctx = canvas.value.getContext('2d');
        if (ctx) {
          canvas.value.width = canvas.value.offsetWidth;
          canvas.value.height = canvas.value.offsetHeight;
          tags = props.tags.map((tag) => ({
            text: tag.name,
            x: Math.random() * canvas!.value!.width,
            y: Math.random() * canvas!.value!.height,
            z: Math.random() * 200 - 100,
            color: tag.color
          }));
          animate();
        }
      }
    };

    const animate = () => {
      if (ctx) {
        if (
          !ctx ||
          !canvas.value ||
          !canvas.value.getContext ||
          !canvas.value.width ||
          !canvas.value.height
        ) {
          return;
        }
        ctx.clearRect(0, 0, canvas.value!.width, canvas.value!.height);
        ctx.font = '20px Arial';

        for (let i = 0; i < tags.length; i++) {
          const tag = tags[i];
          const scale = 100 / (100 - tag.z);
          const alpha = (tag.z + 100) / 200;

          ctx.beginPath();
          ctx.arc(tag.x, tag.y, scale * 2, 0, Math.PI * 2, false);
          ctx.closePath();
          ctx.fillStyle = `rgba(0, 0, 0, ${alpha})`;
          ctx.fill();

          ctx.fillStyle = tag.color;
          ctx.fillText(tag.text, tag.x, tag.y);

          tag.x += Math.cos(angleX) * 0.1;
          tag.y += Math.sin(angleY) * 0.1;
          tag.z -= 0.1;

          if (tag.z < -100) {
            tag.x = Math.random() * canvas.value!.width;
            tag.y = Math.random() * canvas.value!.height;
            tag.z = 100;
          }
        }

        angleX += mouseX * 0.0001;
        angleY += mouseY * 0.0001;

        requestAnimationFrame(animate);
      }
    };

    const handleMouseClick = (event: MouseEvent) => {
      const rect = canvas.value!.getBoundingClientRect();
      mouseX = event.clientX - rect.left - canvas.value!.width / 2;
      mouseY = event.clientY - rect.top - canvas.value!.height / 2;
    };

    onMounted(() => {
      init();
      canvas.value!.addEventListener('click', handleMouseClick);
    });

    onUnmounted(() => {
      if (canvas.value) {
        canvas.value.removeEventListener('click', handleMouseClick);
      }
    });

    return {
      canvas
    };
  }
});
</script>

<style scoped>
.tag-cloud {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
}

canvas {
  width: 100%;
  height: 100%;
}
</style>
